package com.lagou.bean.filter;

import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.common.extension.Activate;
import org.apache.dubbo.rpc.*;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;


@Activate(group = {CommonConstants.CONSUMER,CommonConstants.PROVIDER})
public class DubboInvokeFilter   implements Filter{

    private static ScheduledExecutorService scanDbexec = Executors.newScheduledThreadPool(1);

    public DubboInvokeFilter(){
        scanDbexec.scheduleAtFixedRate(this::showTP, 0, 5, TimeUnit.SECONDS);
    }

    static volatile Map<String, TPCtrl> tpCtrlMap = new ConcurrentHashMap<String, TPCtrl>(128);

    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        long   startTime  = System.currentTimeMillis();
        String methodName = invocation.getMethodName();
        try {
            // 执行方法
            return  invoker.invoke(invocation);
        } finally {
            TPBase base = new TPBase();
            long curr = System.currentTimeMillis();
            base.setCast((int)(curr-startTime));
            base.setOverTime(curr + 60000);
            if (!tpCtrlMap.containsKey(methodName)){
                tpCtrlMap.put(methodName, new TPCtrl());
            }
            tpCtrlMap.get(methodName).addTPList(base);
        }

    }

    public void showTP(){
        try{
            tpCtrlMap.forEach((key, val) -> {
                String show = val.showTP();
                System.out.println(key + " " + show);
            });
        }catch (Exception e){
            e.printStackTrace();
        }

    }



    class TPCtrl{
        private List<TPBase> list = new ArrayList<TPBase>(2048);
        private List<Integer> casts;
        public void addTPList(TPBase base){
            list.add(base);
        }

        public String showTP(){
            int index = list.size()-1;
            while (index>=0){
                if (list.get(0).isOverTime()){
                    list.remove(0);
                    index--;
                }else {
                    break;
                }
            }
            if (index==-1){
                return "总请求数: 0";
            }
            casts = new ArrayList<Integer>(index);
            for(int i=index; i>=0; i--){
                casts.add(list.get(i).getCast());
            }
            Collections.sort(casts);
            return "总请求数: "+casts.size()+"\t TP90: " +casts.get(casts.size()*9/10)+"\t TP99: " +casts.get(casts.size()*99/100);
        }
    }

    class TPBase{
        private long overTime;
        private int cast;

        public long getOverTime() {
            return overTime;
        }

        public void setOverTime(long overTime) {
            this.overTime = overTime;
        }

        public int getCast() {
            return cast;
        }

        public void setCast(int cast) {
            this.cast = cast;
        }

        public boolean isOverTime(){
            return overTime < System.currentTimeMillis();
        }
    }

}
